﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace JESAI.Core.Websocket.Client.Threading
{
    /// <summary>
    /// 类封装SemaphoreSlim，并允许在“使用”块内轻松使用锁定
    /// 无需费心正确发布和处理SemaphoreSlim
    /// <code>
    /// using(await _asyncLock.LockAsync())
    /// {
    ///     // do your synchronized work
    /// }
    /// </code>
    /// </summary>
    public class AsyncLock
    {
        private readonly Task<IDisposable> _releaserTask;
        private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
        private readonly IDisposable _releaser;
        /// <summary>
        /// 类封装SemaphoreSlim，并允许在“使用”块内轻松使用锁定
        /// 无需费心正确发布和处理SemaphoreSlim
        /// </summary>
        public AsyncLock()
        {
            _releaser = new Releaser(_semaphore);
            _releaserTask = Task.FromResult(_releaser);
        }

        /// <summary>
        /// 在“使用”块内使用
        /// </summary>
        public IDisposable Lock()
        {
            _semaphore.Wait();
            return _releaser;
        }

        /// <summary>
        /// 在带有wait的“using”块内使用
        /// </summary>
        public Task<IDisposable> LockAsync()
        {
            var waitTask = _semaphore.WaitAsync();
            return waitTask.IsCompleted
                ? _releaserTask
                : waitTask.ContinueWith(
                    (_, releaser) => (IDisposable)releaser!,
                    _releaser,
                    CancellationToken.None,
                    TaskContinuationOptions.ExecuteSynchronously,
                    TaskScheduler.Default);
        }

        //public async Task<IDisposable> LockAsync()
        //{
        //    if (_semaphore.Wait(0)) // 尝试同步获取
        //        return _releaser;
        //    await _semaphore.WaitAsync().ConfigureAwait(false); // 显式避免上下文捕获
        //    return _releaser;
        //}


        private class Releaser : IDisposable
        {
            private readonly SemaphoreSlim _semaphore;

            public Releaser(SemaphoreSlim semaphore)
            {
                _semaphore = semaphore;
            }

            public void Dispose()
            {
                _semaphore.Release();
            }
        }
    }
}
